package com.orderVideo.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.orderVideo.entity.Video;
import com.orderVideo.exception.BusinessException;
import com.orderVideo.service.VideoService;
import com.orderVideo.mapper.VideoMapper;
import com.orderVideo.utils.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.Base64;

/**
 * @author Sakur
 * @description 针对表【video】的数据库操作Service实现
 * @createDate 2025-03-27 14:43:48
 */
@Slf4j
@Service
public class VideoServiceImpl extends ServiceImpl<VideoMapper, Video>
		implements VideoService {


	@Autowired
	private VideoMapper videoMapper;

	@Value("${video.upload.path}")
	private String videoUploadPath;

	@Value("${video.cover.path}")
	private String videoCoverPath;


	@Override
	public Video uploadVideo(MultipartFile file, String description) throws IOException {
		try {
			long startTime = System.currentTimeMillis(); // 记录开始时间
			// 1. 生成视频ID
			String videoId = IdUtil.getSnowflakeNextIdStr();

			// 2. 获取原始文件名和后缀
			String originalFilename = file.getOriginalFilename();
			String extension = FileUtil.extName(originalFilename);

			// 3. 构建文件路径
			String videoFileName = videoId + "." + extension;
			String videoFilePath = videoUploadPath + videoFileName;
			String coverFileName = videoId + ".jpg";
			String coverFilePath = videoCoverPath + coverFileName;

			// 4. 确保目录存在
			FileUtil.mkdir(videoUploadPath);
			FileUtil.mkdir(videoCoverPath);

			long filestartTime = System.currentTimeMillis();
			// 5. 保存视频文件
			try (InputStream inputStream = file.getInputStream()) {
				FileUtil.writeFromStream(inputStream, videoFilePath);
			}
			long fileEndTime = System.currentTimeMillis();
			log.info("uploadVideo 视频文件操作耗时: {} 秒", (fileEndTime - filestartTime) / 1000); // 计算并打印耗时

			// 6. 截取视频第一帧作为封面
			captureVideoFrame(videoFilePath, coverFilePath);

			// 7. 保存视频信息到数据库
			Video video = new Video();
			video.setVideoId(videoId);
			video.setUserId(LoginUser.getUserId());
			video.setVideoName(originalFilename);
			video.setVideoSource(1); // 默认来源为1
			video.setVideoPushTime(LocalDateTime.now());
			video.setVideoSuffix(extension);
			video.setVideoPath(videoFileName);
			video.setVideoImgPath(coverFileName);
			video.setDescription(description);
			videoMapper.insert(video);
			long endTime = System.currentTimeMillis(); // 记录结束时间
			log.info("uploadVideo 方法耗时: {} 秒", (endTime - startTime) / 1000); // 计算并打印耗时
			return video;
		} catch (Exception e) {
			e.printStackTrace();
			log.error("视频上传失败", e);
			throw new RuntimeException("视频上传失败", e);
		}

	}


	@Override
	public Video getVideoById(Long id) {
		return this.getById(id);
	}

	@Override
	public IPage<Video> getVideoList(IPage<Video> page, Long userId) {
		// 构建查询条件，如果userId不为空，则根据userId筛选
		LambdaQueryWrapper<Video> queryWrapper = new LambdaQueryWrapper<>();
		if (userId != null) {
			queryWrapper.eq(Video::getUserId, userId);
		}
		
		// 按上传时间降序排序，最新上传的视频排在前面
		queryWrapper.orderByDesc(Video::getVideoPushTime);
		
		// 执行分页查询
		return this.page(page, queryWrapper);
	}

	/**
	 * 截取视频第一帧作为封面
	 *
	 * @param videoPath 视频文件路径
	 * @param coverPath 封面保存路径
	 */
	private void captureVideoFrame(String videoPath, String coverPath) {
    // 输入校验
    if (videoPath == null || videoPath.isEmpty() || coverPath == null || coverPath.isEmpty()) {
        throw new IllegalArgumentException("视频路径或封面路径不能为空");
    }

    FFmpegFrameGrabber grabber = null;
    Java2DFrameConverter converter = null;
    // 优化点1: 设置最大重试次数（避免死循环）
    int maxRetry = 100;
    long startTime = System.currentTimeMillis(); // 记录开始时间

    try {
        // 1. 创建视频帧抓取器
        grabber = new FFmpegFrameGrabber(videoPath);
        grabber.start();
        // 2. 创建转换器
        converter = new Java2DFrameConverter();

        // 3. 尝试获取一个有效的视频帧
        Frame frame;
        BufferedImage bufferedImage = null;
        for (int i = 0; i < maxRetry; i++) {
            frame = grabber.grabImage();
            if (frame != null && frame.image != null) {
                bufferedImage = converter.getBufferedImage(frame);
                break;
            }
        }
        // 优化点2: 增加视频流有效性检查
        if (grabber.getLengthInFrames() == 0) {
            throw new RuntimeException("视频无有效帧");
        }

        // 4. 如果获取到了有效帧，保存为图片
        if (bufferedImage != null) {
            ImageIO.write(bufferedImage, "jpg", new File(coverPath));
            log.info("成功截取视频封面：视频路径={}，封面路径={}", videoPath, coverPath);
        } else {
            log.warn("未能获取到有效的视频帧：视频路径={}", videoPath);
            throw new RuntimeException("未能获取到有效的视频帧");
        }
    } catch (FrameGrabber.Exception e) {
        log.error("FFmpegFrameGrabber 操作失败：视频路径={}", videoPath, e);
        throw new RuntimeException("FFmpegFrameGrabber 操作失败", e);
    } catch (IOException e) {
        log.error("保存封面图片失败：封面路径={}", coverPath, e);
        throw new RuntimeException("保存封面图片失败", e);
    } finally {
        // 5. 释放资源
        try {
            if (grabber != null) {
                grabber.stop();
                grabber.release();
            }
        } catch (Exception e) {
            log.error("关闭 FFmpegFrameGrabber 失败：视频路径={}", videoPath, e);
        }

        if (converter != null) {
            converter.close();
        }

        long endTime = System.currentTimeMillis(); // 记录结束时间
        log.info("captureVideoFrame 截取视频封面方法耗时: {} 秒", (endTime - startTime) / 1000); // 计算并打印耗时
    }
}



	private String captureVideoFrame(String videoPath) {
		try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoPath)) {
			grabber.start();
			Frame frame = grabber.grabImage();

			if (frame != null) {
				Java2DFrameConverter converter = new Java2DFrameConverter();
				BufferedImage bufferedImage = converter.convert(frame);

				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				ImageIO.write(bufferedImage, "jpg", baos);
				byte[] imageBytes = baos.toByteArray();

				return "data:image/jpeg;base64," + Base64.getEncoder().encodeToString(imageBytes);
			}
		} catch (Exception e) {
			log.error("Failed to capture video frame", e);
		}
		return null;
	}

}




